using System;
using System.IO;
using EnvDTE;
using Microsoft.Practices.RecipeFramework;
using VSLangProj;
using VSSDKAssist.Assets.Actions.Base;
using VSSDKAssist.Assets.Helpers;
using VsWebSite;

namespace VSSDKAssist.Assets.Actions.VisualStudio.VisualStudio
{
	/// <summary>
	/// Action that add a project reference to a Project
	/// </summary>
	public class AddProjectReferenceAction : ActionBase
	{
		#region Properties
		private Project referringProject;

		/// <summary>
		/// Gets or sets the referring project.
		/// </summary>
		/// <value>The referring project.</value>
		[Input(Required = true)]
		public Project ReferringProject
		{
			get { return referringProject; }
			set { referringProject = value; }
		}

		private string referencedAssembly;

		/// <summary>
		/// Gets or sets the referenced assembly.
		/// </summary>
		/// <value>The referenced assembly.</value>
		[Input(Required = false)]
		public string ReferencedAssembly
		{
			get { return referencedAssembly; }
			set { referencedAssembly = value; }
		}

		private Project referencedProject;

		/// <summary>
		/// Gets or sets the referenced project.
		/// </summary>
		/// <value>The referenced project.</value>
		[Input(Required = false)]
		public Project ReferencedProject
		{
			get { return referencedProject; }
			set { referencedProject = value; }
		}

		#endregion

		/// <summary>
		/// Called when [execute].
		/// </summary>
		protected override void OnExecute()
		{
			if(this.referencedProject != null)
			{
				//Add project reference

				if(this.ReferencedProject.UniqueName.Equals(this.ReferringProject.UniqueName, StringComparison.InvariantCultureIgnoreCase))
				{
					// Do nothing.
					return;
				}

				// If reference already exists, nothing happens.
				// If referringProject is a VSProject
				VSProject vsProject = referringProject.Object as VSProject;
				if(vsProject != null)
				{
					if(VSIPHelper.IsWebProject(referencedProject))
					{
						VsWebSite.VSWebSite vsWebSite = (VsWebSite.VSWebSite)(referencedProject.Object);
						foreach(VsWebSite.WebService webService in vsWebSite.WebServices)
						{
							vsProject.AddWebReference(webService.URL);
						}
					}
					else
					{
						// No error handling needed here. See documentation for AddProject.
						vsProject.References.AddProject(referencedProject);
					}
				}
				else
				{
					// If the Project recived is not a VsProject
					// Try it with a webProject
					VSWebSite webProject = referringProject.Object as VSWebSite;
					if(webProject != null)
					{
						if(VSIPHelper.IsWebProject(referencedProject))
						{
							VSWebSite vsWebSite = (VSWebSite)(referencedProject.Object);
							foreach(VsWebSite.WebService webService in vsWebSite.WebServices)
							{
								webProject.WebReferences.Add(webService.URL, webService.ClassName);
							}
						}
						else
						{
							// Check if the reference already exists in the WebProject
							if(!IsAlreadyReferenced(webProject, referencedProject))
							{
								webProject.References.AddFromProject(referencedProject);
							}
						}
					}
				}
			}
			else if(!String.IsNullOrEmpty(this.referencedAssembly))
			{
				//Add Assembly reference
				VSProject vsProject = referringProject.Object as VSProject;
				string assemblyName = Path.GetFileNameWithoutExtension(this.referencedAssembly);

				if(vsProject != null)
				{
					if(!IsAlreadyReferenced(vsProject, assemblyName))
					{
						vsProject.References.Add(this.referencedAssembly);
					}
				}
				else
				{
					VSWebSite webProject = referringProject.Object as VSWebSite;
					if(webProject != null)
					{
						if(!IsAlreadyReferenced(webProject, assemblyName))
						{
							webProject.References.AddFromFile(this.referencedAssembly);
						}
					}
				}
			}
		}

		/// <summary>
		/// Called when [undo].
		/// </summary>
		protected override void OnUndo()
		{
			//Do Nothing
		}

		#region Private Implementation
		private static bool IsAlreadyReferenced(VSProject vsProject, string assemblyName)
		{
			foreach(Reference reference in vsProject.References)
			{
				if(reference.Name.Equals(assemblyName, StringComparison.InvariantCultureIgnoreCase))
				{
					return true;
				}
			}

			return false;
		}

		private static bool IsAlreadyReferenced(VSWebSite webProject, string assemblyName)
		{
			foreach(AssemblyReference reference in webProject.References)
			{
				if(reference.Name.Equals(assemblyName, StringComparison.InvariantCultureIgnoreCase))
				{
					return true;
				}
			}

			return false;
		}

		private static bool IsAlreadyReferenced(VSWebSite webProject, Project referencedProject)
		{
			foreach(AssemblyReference reference in webProject.References)
			{
				if(reference.Name.Equals(referencedProject.Name, StringComparison.InvariantCultureIgnoreCase))
				{
					return true;
				}
			}

			return false;
		}
		#endregion
	}
}